package lumis.portal.page;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import lumis.portal.PortalException;
import lumis.util.XmlUtil;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Utility class for operating pages' layouts.
 * 
 * @version $Revision: 11804 $ $Date: 2010-07-29 10:06:21 -0300 (Thu, 29 Jul 2010) $
 * @since 5.6.0
 */
public abstract class PageLayoutUtil
{
	/**
	 * Holder identifier used for interfaces without holder.
	 * 
	 * @since 5.6.0
	 */
	public static final String WITHOUT_HOLDER_ID = "WITHOUT_HOLDER_ID";

	/**
	 * Provides a method to resolve a service interface instance identifier into
	 * another one.
	 * 
	 * @version $Revision: 11804 $ $Date: 2010-07-29 10:06:21 -0300 (Thu, 29 Jul 2010) $
	 * @since 5.6.0
	 */
	public static interface IMappingResolver
	{
		/**
		 * Resolves a service interface instance identifier into another one.
		 * 
		 * @param serviceInterfaceInstaceId
		 *            the original identifier.
		 * @return the resolved identifier.
		 * @since 5.6.0
		 */
		public String resolve(String serviceInterfaceInstaceId) throws PortalException;
	}

	/**
	 * Replaces service interface instance identifiers of given {@link Document
	 * layout} using the {@link Map} to resolve the identifiers.
	 * 
	 * @param layout
	 *            the layout to be altered.
	 * @param mapping
	 *            the mapping used to resolve the service interface instance
	 *            identifiers.
	 * @since 5.6.0
	 */
	public static void replaceInterfaceInstanceIds(Document layout, final Map<String, String> mapping) throws PortalException
	{
		replaceInterfaceInstanceIds(layout, new IMappingResolver()
		{
			public String resolve(String key) throws PortalException
			{
				String result = mapping.get(key);
				if (result == null)
					return key;
				else
					return result;
			}
		});
	}

	/**
	 * Replaces service interface instance identifiers of given {@link Document
	 * layout} using the given {@link IMappingResolver} to resolve the
	 * identifiers.
	 * 
	 * @param layoutDocument
	 *            the layout to be altered.
	 * @param resolver
	 *            the resolver that will manage interface instance identifiers
	 *            resolving.
	 * @since 5.6.0
	 */
	public static void replaceInterfaceInstanceIds(Document layoutDocument, IMappingResolver resolver) throws PortalException
	{
		Node[] cellNodes = XmlUtil.selectNodes("layout/area/column/row/cell", layoutDocument);
		if (cellNodes.length > 0)
		{
			for (Node cellNode : cellNodes)
			{
				String oldInterfaceInstanceId = XmlUtil.getTextContent(cellNode);
				String newId = resolver.resolve(oldInterfaceInstanceId);
				if (newId != null)
					XmlUtil.setTextContent(cellNode, newId);
			}
		}
		else
		{
			for (Node interfaceNode : XmlUtil.selectNodes("layout/holder/interface", layoutDocument))
			{
				String oldInterfaceInstanceId = XmlUtil.readAttributeString("id", interfaceNode);
				String newId = resolver.resolve(oldInterfaceInstanceId);
				if (newId != null)
					XmlUtil.addNodeAttr(interfaceNode, "id", newId);
			}
		}
	}

	/**
	 * Gets a {@link List list} of the {@link String service interface instance
	 * identifiers} contained into the {@link Document}.
	 * 
	 * @param document
	 *            the layout document.
	 * @return a list containing the service interface instance identifiers
	 *         contained into the layout document.
	 * @since 5.6.0
	 */
	public static List<String> getLayoutServiceInstanceIds(Document document) throws PortalException
	{
		NodeList nodeList = getInterfaceInstanceNodeList(document);
		ArrayList<String> ret = new ArrayList<String>(nodeList.getLength());
		for (int i = 0; i < nodeList.getLength(); i++)
			ret.add(getNodeInterfaceInstanceId(nodeList.item(i)));

		return ret;
	}

	/**
	 * Gets the service interface instance identifier present into its
	 * {@link Node}.
	 * 
	 * @param interfaceInstanceNode
	 *            the node from where it should be read the service interface
	 *            instance identifier.
	 * @return the service interface instance identifier.
	 * @since 5.6.0
	 */
	public static String getNodeInterfaceInstanceId(Node interfaceInstanceNode) throws PortalException
	{
		return interfaceInstanceNode.getNodeName().equals("cell") ? XmlUtil.getTextContent(interfaceInstanceNode) : XmlUtil
				.readAttributeString("id", interfaceInstanceNode);
	}

	/**
	 * Gets a {@link List list} with the service interface instance {@link Node
	 * nodes} present into the given layout {@link Document document}.
	 * 
	 * @param document
	 *            the layout document.
	 * @return a list with the service interface instance identifiers.
	 * @since 5.6.0
	 */
	public static List<Node> getLayoutInterfaceInstanceNodes(Document document)
	{
		NodeList nodeList = getInterfaceInstanceNodeList(document);
		ArrayList<Node> ret = new ArrayList<Node>(nodeList.getLength());
		for (int i = 0; i < nodeList.getLength(); i++)
			ret.add(nodeList.item(i));

		return ret;
	}

	/**
	 * Gets a {@link NodeList node list} of the service interface instances
	 * contained into the given layout {@link Document document}.
	 * 
	 * @param document
	 *            the layout document.
	 * @return a node list of the service interface instances contained into the
	 *         given layout document.
	 * @since 5.6.0
	 */
	public static NodeList getInterfaceInstanceNodeList(Document document)
	{
		NodeList nodeList = document.getElementsByTagName("cell");
		final boolean usesCellLayout = nodeList.getLength() > 0;
		if (!usesCellLayout)
			nodeList = document.getElementsByTagName("interface");
		return nodeList;
	}

	/**
	 * Sets the service interface instance identifier to the given {@link Node
	 * service interface instance node}.
	 * 
	 * @param node
	 *            the service interface instance node.
	 * @param serviceInterfaceInstanceId
	 *            the service interface instance identifier ti be set.
	 * @since 5.6.0
	 */
	public static void setServiceInterfaceInstanceIdInNode(Node node, String serviceInterfaceInstanceId)
	{
		if (node.getNodeName().equals("cell"))
			XmlUtil.setTextContent(node, serviceInterfaceInstanceId);
		else
			XmlUtil.addNodeAttr(node, "id", serviceInterfaceInstanceId);
	}
}
